package com.mspbots.attendance.trigger;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.mspbots.api.client.CoreClient;
import com.mspbots.attendance.model.TenantUserWorkScheduleDTO;
import com.mspbots.attendance.model.TriggerEventDTO;
import com.mspbots.attendance.request.TenantDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.DayOfWeek;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

import static com.mspbots.common.TriggerEvent.ATTENDANCE_SCHEDULE;

@Slf4j
@Component
public class AttendanceTriggerEvent {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitMessagingTemplate messagingTemplate;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private CoreClient coreClient;

    private static final String REDIS_KEY_PREFIX_TENANT = "MSPBOTS:CONFIG:TENANT:";

//    @Scheduled(initialDelay = 10000, fixedRate = 60 * 1000)
    @Scheduled(initialDelay = 10000, fixedRateString = "${mspbots.fixedDelay.attendanceTrigger}")
    public void produce() {
        log.debug("attendance schedule...");
        List tenants = redisTemplate.opsForList().range(REDIS_KEY_PREFIX_TENANT + "tenants", 0, -1);
        log.debug("tenants ...  {}", tenants);
        List<TenantDTO> tenantDTOS = objectMapper.convertValue(tenants, new TypeReference<List<TenantDTO>>() {
        });
        log.debug("tenantDTOS ...  {}", tenantDTOS);
        tenantDTOS.stream().filter(item -> item.getStatusId() == 1).forEach(tenantDTO -> {
            JsonNode userWorkSchedule = coreClient.get("/user-work-schedule/findUserSchedule/" + tenantDTO.getId()).block();
            List<TenantUserWorkScheduleDTO> tenantUserWorkScheduleDTO = objectMapper.convertValue(userWorkSchedule, new TypeReference<List<TenantUserWorkScheduleDTO>>() {
            });

            tenantUserWorkScheduleDTO.parallelStream().forEach(schedule -> {
                ZonedDateTime zonedTimeNow = ZonedDateTime.now(ZoneId.of(schedule.getTimezoneOffset()));
                DayOfWeek dayOfWeek = zonedTimeNow.getDayOfWeek();
                schedule.getWorkScheduleList().stream().filter(item ->
                        item.getDayOfWeek().equals(dayOfWeek.name())).forEach(workTime -> {
                    LocalTime beginTime = workTime.getBeginTime();
                    LocalTime endTime = workTime.getEndTime();
                    if (StringUtils.isEmpty(beginTime) || StringUtils.isEmpty(endTime)) {
                        return;
                    }
                    ObjectNode payload = this.objectMapper.createObjectNode();
                    ZonedDateTime zonedStartTimeWork = ZonedDateTime.of(zonedTimeNow.toLocalDate(), beginTime, ZoneId.of(schedule.getTimezoneOffset()));
                    ZonedDateTime zonedEndTimeWork = ZonedDateTime.of(zonedTimeNow.toLocalDate(), endTime, ZoneId.of(schedule.getTimezoneOffset()));
                    payload.put("startTime", DateTimeFormatter.ISO_ZONED_DATE_TIME.format(zonedStartTimeWork));
                    payload.put("endTime", DateTimeFormatter.ISO_ZONED_DATE_TIME.format(zonedEndTimeWork));
                    payload.put("configId", workTime.getId());

                    if(!ObjectUtils.isEmpty(schedule.getTenantUserId())) {
                        Map<String, Object> params = Map.of(
                                "tenantId", schedule.getTenantId(),
                                "tenantUserId", schedule.getTenantUserId()
                        );
                        JsonNode userMapping = coreClient.get("/user-mapping/detail", params).block();


                        if (!ObjectUtils.isEmpty(userMapping)) {
                            TriggerEventDTO triggerEventDTO = new TriggerEventDTO();
                            triggerEventDTO.setTenantId(schedule.getTenantId());
                            triggerEventDTO.setEventName(ATTENDANCE_SCHEDULE.getEvent());
                            triggerEventDTO.setScope(ATTENDANCE_SCHEDULE.getScope());
                            triggerEventDTO.setPayload(payload);
                            triggerEventDTO.setUserInfo(userMapping);
                            this.messagingTemplate.convertAndSend("msp.trigger.event", "", triggerEventDTO);
                            log.debug("cw msp.trigger.event Attendance Schedule:[{}] ", this.objectMapper.convertValue(triggerEventDTO, JsonNode.class));
                        }
                    }
                });
            });
        });

    }
}
